package com.yy.micro.magic.core.filter;

import com.yy.micro.magic.core.annotation.Filter;
import com.yy.micro.magic.core.condition.FilterCondition;
import com.yy.micro.magic.core.config.Content;
import com.yy.micro.magic.core.model.ResultCollector;
import com.yy.micro.magic.core.model.RuntimeMetadata;
import com.yy.micro.magic.ext.domain.filter.DynamicTrigger;

import org.springframework.util.StringUtils;

import java.util.regex.Pattern;
 /**
   * @author YY
   * @version 1.0.0
   * @update 2021/9/20 10:38 下午
   * @description: Filter调度的核心类。MagicFilter在运行过程中是以链表的形态存在的，
  * FilterChain结构包含了当前MagicFilter和下一个节点，当next为null时，表示已到了最后。
 */
public class FilterChain{

    /**
     * 当前责任链中的过滤器
     */
    private MagicFilter current;

    /**
     * 下一个过滤链节点
     */
    private FilterChain next;

    public FilterChain(final MagicFilter filter, final FilterChain next) {
        this.current = filter;
        this.next = next;
    }

     /**
      * 判断当前MagicFilter是否符合执行条件，如果不符合，则跳到下一个{@link FilterChain}
      * @param metadata 运行时源数据当前数据节点元数据
      * @param collector  结果收集器，在运行过程中，收集各节点产生的结果。
      */
    public void doFilter(final RuntimeMetadata metadata, final ResultCollector collector) {
        if (null != current) {
            if ( match(metadata, collector)) {// 匹配processor和pattern,策略
                current.doFilter(metadata, collector, next);
            } else {
                if (null != next) {// 如查当前Filter为null，则判断下一个节点是否为null，不为null时，执行下一个节点
                    next.doFilter(metadata, collector);
                }
            }
        } else if (null != next) {
            next.doFilter(metadata, collector);
        }
    }

    /**
     * 匹配当前的执行元数据{@link RuntimeMetadata}与{@link Filter#conditions()}中指定的条件是否通过正则校验。
     *
     * @param metadata {@link RuntimeMetadata}
     * @param collector
     * @return
     */
    protected boolean match(final RuntimeMetadata metadata, ResultCollector collector) {
        final String key = metadata.getKey();
        final Filter mFilter = current.getClass().getAnnotation(Filter.class);
        if (Content.STRATEGY_MAP_FILTER.equals(mFilter.value())){
            return true;
        }
        String[] patterns = mFilter.conditions();
        if (null == patterns || patterns.length < 1) {
            if (current instanceof DynamicRuleMagicFilter){
                DynamicTrigger dynamicTrigger = ((DynamicRuleMagicFilter) current).getTrigger(metadata);
                if (null != dynamicTrigger){
                    return true;
                }
            }
            final FilterCondition condition = findCondition(mFilter,metadata);
            if (null != condition){
                return condition.match(metadata);
            }
            return false;
        }
        return matchPatterns(patterns,mFilter.regular(),metadata);
    }


    private FilterCondition findCondition(Filter filter, RuntimeMetadata metadata){
        Class<? extends FilterCondition> condition = filter.condition();
        if (null != condition){
            return metadata.getRequest().getContext().getApplicationContext().getBean(condition);
        }
        return null;
    }

    private boolean matchPatterns(String[] patterns, boolean regular,RuntimeMetadata metadata){
        for (String pattern : patterns){
            if (!StringUtils.isEmpty(pattern) ){
                if (!regular){
                    pattern = replacePatternToRegular(pattern);
                }
                if (Pattern.matches(pattern,metadata.getKey())){
                    return true;
                }
            }
        }
        return false;
    }


    private String replacePatternToRegular(String pattern) {
        if (pattern.contains("-*")) {
            pattern = pattern.replaceAll("-[*]", "-[\\\\d]+");// 替换pattern中-*为数字正则表达式，
        }
        if (pattern.contains("**")) {
            pattern = pattern.replaceAll("[**]", "[\\\\w|\\\\W]+");// 替换pattern中所有的*为正则中的任意字符校验
        }
        if (pattern.contains("*")) {
            pattern = pattern.replaceAll("[*]", "[\\\\w]*");// 替换pattern中所有的*为正则中的[a-zA-Z0-9]字符校验
        }
        return pattern;
    }

    /**
     * 下一个Filter节点
     *
     * @param next
     *            the next to set
     */
    public void setNext(final FilterChain next) {
        this.next = next;
    }

}
